/**
 * Created by hjqi on 2016/8/30.
 */

//db
var clusterMetaInfoDB = require('../../db/clusterMetaInfoDB');
var _clusterMetaInfoDB = new clusterMetaInfoDB();

//third part lib
var uuid = require('../common/common').generateUUID;
var logger = require('../log4js/log4js').logger('cluster');
var common = require('../common/common');

module.exports = cluster;

function cluster(){

}

cluster.prototype.getClusters = function(ns,clusterId){
    return new Promise(function(resolve, reject){
        var query = {
            namespaces:ns
        };

        if(clusterId !== undefined)
            query.clusterId = clusterId;

        _clusterMetaInfoDB.getWithParam(null, query, function(err,rets){
            if (err) {
                logger.error("username " + ns + " get cluster from db:" + err);
                reject(err);
            }else {
                resolve(rets);
            }
        });
    });
}

cluster.prototype.createCluster = function(ns,name){
    return new Promise(function(resolve, reject){
        var data = {
            namespaces:ns,
            name:name
        };
        var _clusterId = uuid(32,16);
        data.clusterId = _clusterId;

        _clusterMetaInfoDB.insert(null, data, function(err,rets){
            if (err) {
                logger.error("username " + ns + " create cluster from db:" + err);
                reject(err);
            }else {
                resolve({
                    ret:true,
                    data:rets
                });
            }
        });
    });
}

cluster.prototype.deleteCluster = function(ns,clusterId){

    return new Promise(function(resolve, reject){
        var data = {
            namespaces:ns,
            clusterId:clusterId
        };

        _clusterMetaInfoDB.delWithParam(null, data, function(err,rets){
            if (err) {
                logger.error("username " + ns + " delete cluster from db:" + err);
                reject(err);
            }else {
                resolve(true);
            }
        });
    });
}

//maybe useless
cluster.prototype.checkClusterNode = function(ns,clusterId,token){

    return new Promise(function(resolve, reject){
        var _data = common.decodeTokenData(token);
        var nodeId = _data.id;
        var query = {
            namespaces:ns,
            clusterId:clusterId
        };
        query["nodes."+nodeId] = {$exists: true};

        _clusterMetaInfoDB.getWithParam(null, query, function(err,rets){
            if (err) {
                logger.error("username " + ns + " check cluster from db:" + err);
                reject(err);
            }else {
                resolve(rets);
            }
        });

    });


}

cluster.prototype.checkClusterNode_v2 = function(nodeInfo,nodeId){
    var _ret = false;
    var _nodeinfo_obj = JSON.parse(nodeInfo);
    _nodeinfo_obj.items.forEach(function(node){
        if(node.metadata.labels.nodeId === nodeId)
            _ret  = true;
    });
    return _ret;
}

cluster.prototype.getClusterToken = function(ns,clusterId) {

    return new Promise(function (resolve, reject) {
        var query = {
            namespaces: ns,
            clusterId: clusterId
        };

        _clusterMetaInfoDB.getWithParam(null, query, function (err, rets) {
            if (err) {
                logger.error("username " + ns + " get cluster  from db:" + err);
                reject(err);
            } else {
                if(rets.length > 0){
                    var _clusterInfo = rets[0];
                    var _data = {
                        id:uuid(32,16),
                        clusterId:clusterId
                    };
                    if(_clusterInfo.masterId === undefined){
                        //generate master info token
                        _data.role = 'master';
                        _data.masterIp = '127.0.0.1';
                    }else{
                        //generate slave info token
                        _data.role = 'minion';
                        //get master ip
                        _data.masterIp = _clusterInfo.nodes[_clusterInfo.masterId].host;
                    }
                    //var token = jwt.sign(_data,"naturecloud");
                    resolve(common.encodeTokenData(_data));
                }else{
                    reject({
                        message:'get cluster info error'
                    });
                }

            }
        });

    });

}

cluster.prototype.setClusterNodeInfo = function(nodeInfo,nodes){

    var _ip2idMap = {};
    var _nodeinfo_obj = JSON.parse(nodeInfo);
    //format node list to node map
    if(_nodeinfo_obj.items.length > 0){
        /*nodes.forEach(function(node){
            _nodeMap[node.host] = node;
        });*/
        for(var i in nodes){
            _ip2idMap[nodes[i].host] = nodes[i];
        }
    }
    //add more info
    _nodeinfo_obj.items.forEach(function(node){
        if(_ip2idMap[node.metadata.name] !== undefined){
            var _node = _ip2idMap[node.metadata.name];
            _node.status = getNodeStatus(node.status.conditions);
            _node.cpu = getNodeCpu(node.status.capacity);
            _node.memory = getNodeMem(node.status.capacity);
        }
    });
    return nodes;
}

cluster.prototype.deleteClusterNode = function(ns,clusterId,nodeId){

    return new Promise(function(resolve, reject) {

        getNodeStatusFromDB(clusterId,nodeId).then(function(ret){

            //return can't find cluster info
            if(ret.ret  === false){
                resolve(ret);
            }

            //return must delete minion node first
            if(ret.masterId === nodeId && ret.nodesnum > 1){
                resolve({
                    ret:false,
                    message:'please delete minion node first'
                });
            }

            var query = {
                clusterId: clusterId
            };
            var _nodeId = nodeId;
            query["nodes." + _nodeId + ".status"] = "disconnected";

            var _data = {
                $unset: {

                }
            }
            _data["$unset"]["nodes."+_nodeId]  = 1;

            if(ret.masterId === nodeId)
                _data["$unset"]["masterId"] = 1;

            _clusterMetaInfoDB.updateFieldExt(null, query, _data, function (err, rets) {
                if (err) {
                    logger.error("username " + ns + " check cluster from db:" + err);
                    reject(err);
                } else {
                    if (rets.n > 0) {
                        resolve({
                            ret: true
                        });
                        resolve
                    } else {
                        resolve({
                            ret: false,
                            message: 'must remove agent in remote server before delete node'
                        });
                    }
                }
            });
        }).catch(function(err){

        });


    });

}

cluster.prototype.getNodeInfo = function(clusterId,nodeId){
    return new Promise(function(resolve, reject) {
        getNodeStatusFromDB(clusterId, nodeId).then(function (ret) {
            resolve(ret);
        }).catch(function (err) {
            reject(err);
        });
    });
}

function getNodeStatus(conds){

    var _ret = 'not_ready';
    for(var i=0;i<conds.length;i++){
        if(conds[i].type == 'Ready'){
            if(conds[i].status == 'True')
                _ret = 'ready';
            break;
        }
    }
    return _ret;
}

function getNodeCpu(cap){
    return cap.cpu;
}

function getNodeMem(cap){
    var _ret;
    var _mem = cap.memory.substr(0,cap.memory.length-2);
    if(cap.memory.substr(cap.memory.length-2) === 'Ki')
        _ret = (_mem/1024).toFixed(2);
    else if(cap.memory.substr(cap.memory.length-2) === 'Mi')
        _ret = _mem;
    return _ret;
}

function getNodeStatusFromDB(clusterId,nodeId){
    return new Promise(function(resolve, reject) {
        var query = {
            clusterId: clusterId
        };
        _clusterMetaInfoDB.getWithParam(null, query, function (err, rets) {
            if (err) {
                logger.error(" get cluster  from db:" + err);
                reject(err);
            } else {
                if(rets.length > 0){

                    resolve({
                        ret:true,
                        connected:rets[0].nodes[nodeId].status,
                        masterId:rets[0].masterId,
                        nodesnum:getNodesNum(rets[0].nodes)
                    });
                }else{
                    resolve({
                        ret:false,
                        message:'can not find cluster info'
                    });
                }
            }
        });
    });
}

function getNodesNum(nodes){
    var _num = 0;
    for(var i in nodes){
        _num++;
    }
    return _num;
}